package com.gitee.wsl.math.regressions

import com.gitee.wsl.ext.array.mean
import kotlin.math.pow

class Linear {
    private var x: DoubleArray
    private var y: DoubleArray

    val a: Double
    val b: Double

    constructor(x: DoubleArray, y: DoubleArray) {
        if (x.size != y.size) {
            throw IllegalArgumentException("size of x ${x.size} does not equal size of y ${y.size}")
        }

        this.x = x
        this.y = y

        b = calcB()
        a = calcA()
    }

    constructor(x: IntArray, y: IntArray) :
            this(x.map { it.toDouble() }.toDoubleArray(), y.map { it.toDouble() }.toDoubleArray())

    constructor(xy: Array<Pair<Double, Double>>) :
            this(xy.map { it.first }.toDoubleArray(), xy.map { it.second }.toDoubleArray())

    fun y(x: Double): Double {
        return a + b * x
    }

    fun y(x: Int): Double {
        return y(x.toDouble())
    }

    fun summary(): Nothing = throw NotImplementedError()

    private fun calcB(): Double {
        val sumX = x.sum()
        val denominator = (x.size * x.sumOf { it.pow(2) } - sumX.pow(2))

        if (denominator == 0.0) {
            return 1.0
        }

        return ((x.size * (x.mapIndexed { index, d -> d * y[index] }).sum()) - sumX * y.sum()) /
                denominator
    }

    private fun calcA(): Double {
        return y.mean - b * x.mean
    }
}